require 'net/http'
require 'uri'
require 'yaml'
require 'fileutils'
require 'system_util'

class Fetcher

  def self.down_to_home(global, target_mod, check_file)
    down_url = global.download_url(target_mod)
    tarball = File.join(global.cache_path, File.basename(down_url))
    target_dir = global.home_target_dir(target_mod)
    fetch(tarball, down_url)
    unpack_tar_gz_and_check(tarball, target_dir+'_tmp', target_dir, check_file)
    if File.exist?(target_dir+'_tmp')
      FileUtils.rm_rf(target_dir+'_tmp')
    end
  end

  def self.unpack_tar_gz_and_check(tar_gz_file, tar_out_dir, target_dir, need_exist_file_in_target_dir)
    print "Unpacking #{tar_gz_file} ... "
    FileUtils.mkdir_p(tar_out_dir)
    tar_output = SystemUtil.run_with_err_output "tar pxzf #{tar_gz_file} -C #{tar_out_dir}"
    FileUtils.rm_rf tar_gz_file

    mv_tar_out_dir_to_target_dir(tar_out_dir, target_dir)

    unless File.exists?(File.join(target_dir, need_exist_file_in_target_dir))
      puts "Unable to retrieve [#{need_exist_file_in_target_dir}] ... Failed"
      puts tar_output
      exit 1
    end
    puts 'OK'
  end

  def self.mv_tar_out_dir_to_target_dir(tar_out_dir, target_dir)
    FileUtils.mkdir_p(target_dir)
    FileUtils.rm_rf(target_dir)

    entries = Dir.entries(tar_out_dir)
    file_cnt = entries.length
    if file_cnt > 3
      FileUtils.mv(tar_out_dir, target_dir)
    else
      real_dir = entries.detect do |entry|
        entry != '.' and entry != '..'
      end
      FileUtils.mv(File.join(tar_out_dir, real_dir), target_dir)
    end
  end

  def self.fetch(file_path, url)
    print "Downloading from #{url} ... "

    dir = File.dirname(file_path)
    FileUtils.mkdir_p(dir)
    File.open(file_path, 'w') do |tf|
      begin
        Net::HTTP.get_response(URI.parse(url)) do |response|
          unless response.is_a?(Net::HTTPSuccess)
            puts 'Could not fetch file (%s): %s/%s' % [file_path, response.code, response.body]
            return
          end

          response.read_body do |segment|
            tf.write(segment)
          end
        end
      ensure
        tf.close
      end
    end
    puts 'OK'
    file_path
  end

end